#pragma once
// 实现语音识别子服务
/*
    1.包含语音识别客户端
    2.包含brpc服务器，其中实现SpeechServiceImpl为调用语音客户端对语音信息进行识别
    3.服务器注册客户端etcd
*/
#include <brpc/server.h>
#include <butil/logging.h>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "logger.hpp" //日志模块封装
#include "etcd.hpp"   //服务注册模块封装
#include "data_es.hpp" //es数据管理客户端的封装
#include "mysql_message.hpp" //mysql数据管理客户端的封装

#include "message.pb.h"  //protobuf框架代码
#include "base.pb.h"  
#include "file.pb.h"  //文件的上传和下载
#include "user.pb.h"

#include "utils.hpp"
#include "channel.hpp"
#include "rabbitmq.hpp"
#include "utils.hpp"

/*
    用户管理子模块相比文件管理子模块多了信道管理对象、服务发现对象、文件子服务名称
    因为头像是存储在文件系统的，通过文件服务名称在信道管理对象找到文件子服务的信道
    调用文件子服务进行通信，获取头像

    服务发现对象没用到

    ServiceManager::ptr _mm_channel; //RPC信道管理对象,进行文件子服务的rpc，请求进行头像的文件下载
    std::string _file_name_service; //文件子服务的名称
    Discovery::ptr _service_discoverer;                 //服务发现对象
*/

namespace zrb
{
    // （1）.创建rpc服务子类继承pb中的EchoService服务类，并实现内部的业务接口逻辑
    class MessageServiceImpl : public zrb::MsgStorageService 
    {
    public:
        MessageServiceImpl(std::shared_ptr<odb::core::database> _mysql_odb,
            std::shared_ptr<elasticlient::Client> _es_client,
            const ServiceManager::ptr& mm_channel,
            const std::string& file_name_service,
            const std::string& user_name_service)
            : _mysql_handle(std::make_shared<MessageTable>(_mysql_odb))
            , _es_handle(std::make_shared<ESMessage>(_es_client))
            , _mm_channel(mm_channel)
            , _file_name_service(file_name_service)
            ,_user_name_service(user_name_service)
        {
             _es_handle->createIndex(); //创建索引
        }

        ~MessageServiceImpl()
        {
        }

        virtual void GetHistoryMsg(::google::protobuf::RpcController* controller,
                    const ::zrb::GetHistoryMsgReq* request,
                    ::zrb::GetHistoryMsgRsp* response,
                    ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard rpc_guard(done);
            //定义一个错误回调函数
            auto err_response = [this,response](const std::string& id,const std::string& errmsg){
                response->set_request_id(id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };

            //1.提取关键要素 - 会话ID、起始时间、结束时间
            std::string request_id = request->request_id();
            std::string session_id = request->chat_session_id();
            boost::posix_time::ptime stime = boost::posix_time::from_time_t(request->start_time());
            boost::posix_time::ptime etime = boost::posix_time::from_time_t(request->over_time());
            //2.从数据库中进行消息查询
            auto message_lists = _mysql_handle->range(session_id,stime,etime);
            //3.统计所有文件类型消息的文件ID，并从文件子服务进行批量下载
            std::unordered_set<std::string> file_id_lists;
            for(auto& message : message_lists)
            {
                if(message.file_id().empty())
                {
                    continue;
                }
                file_id_lists.insert(message.file_id());
            }
            std::unordered_map<std::string,std::string> file_data_lists;
            bool ret = _GetFile(request->request_id(),file_id_lists,file_data_lists);
            if(!ret)
            {
                LOG_ERROR("获取批量文件数据失败");
                return err_response(request_id,"获取批量文件数据失败");
            }
            //4.统计所有消息的发送者用户ID，从用户子服务进行批量用户信息获取
            std::unordered_set<std::string> user_id_lists;
            // LOG_DEBUG("用户ID的个数是{}",message_lists.size());
            for(auto& message : message_lists)
            {
                LOG_DEBUG("用户ID{}",message.user_id());
                user_id_lists.insert(message.user_id());
            }
            std::unordered_map<std::string,UserInfo> user_lists;
            ret = _GetUser(request_id,user_id_lists,user_lists);
            if (ret == false) 
            {
                LOG_ERROR("{} 批量用户数据获取失败！", request_id);
                return err_response(request_id, "批量用户数据获取失败!");
            }
            //5.组织响应
            response->set_request_id(request->request_id());
            response->set_success(true);
            for(auto& message : message_lists)
            {
                // LOG_DEBUG("用户ID的个数是{}",message_lists.size());
                // std::cout << 111 << " "<< message.user_id() << " " << message.message_type() << std::endl;
                MessageInfo* message_info = response->add_msg_list();
                message_info->set_message_id(message.message_id());
                message_info->set_chat_session_id(message.session_id());
                message_info->set_timestamp(boost::posix_time::to_time_t(message.create_time()));
                message_info->mutable_sender()->CopyFrom(user_lists[message.user_id()]);
                switch(message.message_type())
                {
                    case MessageType::STRING:
                        message_info->mutable_message()->set_message_type(MessageType::STRING); //设置数据类型
                        message_info->mutable_message()->mutable_string_message()->set_content(message.content());
                        break;
                    case MessageType::IMAGE:
                        message_info->mutable_message()->set_message_type(MessageType::IMAGE); //设置数据类型
                        message_info->mutable_message()->mutable_image_message()->set_file_id(message.file_id());
                        message_info->mutable_message()->mutable_image_message()->set_image_content(file_data_lists[message.file_id()]);
                        break;
                    case MessageType::FILE:
                        message_info->mutable_message()->set_message_type(MessageType::IMAGE); //设置数据类型
                        message_info->mutable_message()->mutable_file_message()->set_file_id(message.file_id());
                        message_info->mutable_message()->mutable_file_message()->set_file_size(message.file_size());
                        message_info->mutable_message()->mutable_file_message()->set_file_name(message.file_name());
                        message_info->mutable_message()->mutable_file_message()->set_file_contents(message.content());
                        break;
                    case MessageType::SPEECH:
                        message_info->mutable_message()->set_message_type(MessageType::SPEECH);
                        message_info->mutable_message()->mutable_speech_message()->set_file_id(message.file_id());
                        message_info->mutable_message()->mutable_speech_message()->set_file_contents(file_data_lists[message.file_id()]);
                        break;
                    default:
                        LOG_ERROR("消息类型错误 {}-{}",message.message_id(),message.message_type());
                        return;
                }
            }
            return;
        }

        virtual void GetRecentMsg(::google::protobuf::RpcController* controller,
                            const ::zrb::GetRecentMsgReq* request,
                            ::zrb::GetRecentMsgRsp* response,
                            ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard rpc_guard(done);
            //定义一个错误回调函数
            auto err_response = [this,response](const std::string& id,const std::string& errmsg){
                response->set_request_id(id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };

            //1.提取请求中的关键要素，请求ID，会话ID，要获取的消息数量
            std::string rid = request->request_id();
            std::string ssid = request->chat_session_id();
            int msg_count = request->msg_count();
            //2.从数据库，获取最近的消息元信息
            auto msg_lists = _mysql_handle->recent(ssid,msg_count);
            //3.统计所有文件类型消息的文件ID，并从文件子服务进行批量下载
            std::unordered_set<std::string> file_id_lists;
            for(auto& message : msg_lists)
            {
                if(message.file_id().empty())
                {
                    continue;
                }
                file_id_lists.insert(message.file_id());
            }
            unordered_map<std::string,std::string> file_data_lists;
            bool ret = _GetFile(request->request_id(),file_id_lists,file_data_lists);
            if(!ret)
            {
                LOG_ERROR("获取批量文件数据失败");
                return err_response(rid,"获取批量文件数据失败");
            }
            //4.统计所有消息的发送者用户ID，从用户子服务进行批量用户信息获取
            std::unordered_set<std::string> user_id_lists;
            for(auto& message : msg_lists)
            {
                user_id_lists.insert(message.user_id());
            }
            std::unordered_map<std::string,UserInfo> user_lists;
            ret = _GetUser(rid,user_id_lists,user_lists);
            if (ret == false) 
            {
                LOG_ERROR("{} 批量用户数据获取失败！", rid);
                return err_response(rid, "批量用户数据获取失败!");
            }
            //5.组织响应
            response->set_request_id(request->request_id());
            response->set_success(true);
            for(auto& message : msg_lists)
            {
                MessageInfo* message_info = response->add_msg_list();
                message_info->set_message_id(message.message_id());
                message_info->set_chat_session_id(message.session_id());
                message_info->set_timestamp(boost::posix_time::to_time_t(message.create_time()));
                message_info->mutable_sender()->CopyFrom(user_lists[message.user_id()]);
                switch(message.message_type())
                {
                    case MessageType::STRING:
                        message_info->mutable_message()->set_message_type(MessageType::STRING); //设置数据类型
                        message_info->mutable_message()->mutable_string_message()->set_content(message.content());
                        break;
                    case MessageType::IMAGE:
                        message_info->mutable_message()->set_message_type(MessageType::IMAGE); //设置数据类型
                        message_info->mutable_message()->mutable_image_message()->set_file_id(message.file_id());
                        message_info->mutable_message()->mutable_image_message()->set_image_content(file_data_lists[message.file_id()]);
                        break;
                    case MessageType::FILE:
                        message_info->mutable_message()->set_message_type(MessageType::IMAGE); //设置数据类型
                        message_info->mutable_message()->mutable_file_message()->set_file_id(message.file_id());
                        message_info->mutable_message()->mutable_file_message()->set_file_size(message.file_size());
                        message_info->mutable_message()->mutable_file_message()->set_file_name(message.file_name());
                        message_info->mutable_message()->mutable_file_message()->set_file_contents(message.content());
                        break;
                    case MessageType::SPEECH:
                        message_info->mutable_message()->set_message_type(MessageType::SPEECH);
                        message_info->mutable_message()->mutable_speech_message()->set_file_id(message.file_id());
                        message_info->mutable_message()->mutable_speech_message()->set_file_contents(file_data_lists[message.file_id()]);
                    default:
                        LOG_ERROR("消息类型错误");
                        return;
                }
            }
            return;
        }

        virtual void MsgSearch(::google::protobuf::RpcController* controller,
                            const ::zrb::MsgSearchReq* request,
                            ::zrb::MsgSearchRsp* response,
                            ::google::protobuf::Closure* done)
        {
            brpc::ClosureGuard rpc_guard(done);
            //定义一个错误回调函数
            auto err_response = [this,response](const std::string& id,const std::string& errmsg){
                response->set_request_id(id);
                response->set_success(false);
                response->set_errmsg(errmsg);
                return;
            };

            //关键字的消息搜索，只针对文本消息
            //1.从请求中提取关键要素：请求ID、会话ID、关键字
            std::string rid = request->request_id();
            std::string ssid = request->chat_session_id();
            std::string skey = request->search_key();
            //2.从ES搜索引擎中进行关键字消息搜索，得到消息列表
            auto msg_lists = _es_handle->search(skey,ssid);
            //3.组织所有消息的用户ID，从用户子服务获取用户信息
            std::unordered_set<std::string> user_id_lists;
            for(auto& message : msg_lists)
            {
                user_id_lists.insert(message.user_id());
            }
            std::unordered_map<std::string,UserInfo> user_lists;
            bool ret = _GetUser(rid,user_id_lists,user_lists);
            if (ret == false) 
            {
                LOG_ERROR("{} 批量用户数据获取失败！", rid);
                return err_response(rid, "批量用户数据获取失败!");
            }
            //4.组织响应
            response->set_request_id(request->request_id());
            response->set_success(true);
            for(auto& message : msg_lists)
            {
                MessageInfo* message_info = response->add_msg_list();
                message_info->set_message_id(message.message_id());
                message_info->set_chat_session_id(message.session_id());
                message_info->set_timestamp(boost::posix_time::to_time_t(message.create_time()));
                message_info->mutable_sender()->CopyFrom(user_lists[message.user_id()]);
                message_info->mutable_message()->set_message_type(MessageType::STRING); //设置数据类型
                message_info->mutable_message()->mutable_string_message()->set_content(message.content());
            }
            return;
        }

        void onMessage(const char* body,size_t sz)
        {
            //1.取出序列化的消息内容，进行反序列化
            zrb::MessageInfo message;
            bool ret = message.ParseFromArray(body,sz);
            if(ret == false)
            {
                LOG_ERROR("反序列化消息失败");
                return;
            }

            std::string file_id,file_content,file_name; //方便存入数据库时的内容获取 
            unsigned int file_size; 
            //2.根据不同的消息类型进行不同的处理
            switch(message.message().message_type())
            {
                //如果是是文本消息，取元信息存储到ES中
                case MessageType::STRING:
                {
                    file_content = message.message().string_message().content();
                    file_size = message.message().string_message().content().size();

                    ret = _es_handle->appendData(message.sender().user_id(),
                        message.message_id(),
                        message.timestamp(),
                        message.chat_session_id(),
                        message.message().string_message().content());
                    if(ret == false)
                    {
                        LOG_ERROR("{}文本消息存储进es搜索引擎失败",message.message_id());
                        return;
                    }
                }
                break;

                //如果是图片消息
                case MessageType::IMAGE:
                {
                    const auto& msg = message.message().image_message();

                    file_id = msg.file_id();
                    file_content = msg.image_content();
                    file_size = msg.image_content().size();

                    ret = _PutFile("",msg.image_content(),msg.image_content().size(),file_id);
                    if(ret == false)
                    {
                        LOG_ERROR("上传图片到文件系统失败");
                        return;
                    }
                }
                break;

                //如果是文件消息
                case MessageType::FILE:
                {
                    const auto& file =  message.message().file_message();

                    file_content = file.file_contents();
                    file_size = file.file_size();
                    file_name = file.file_name();
                    file_id = file.file_id();

                    ret = _PutFile(file.file_name(),file.file_contents(),file.file_size(),file_id);
                    if(ret == false)
                    {
                        LOG_ERROR("上传文件到文件系统失败");
                        return;
                    }
                }
                break;

                //如果是语音消息
                case MessageType::SPEECH:
                {
                    const auto& msg = message.message().speech_message();

                    file_content = msg.file_contents();
                    file_id = msg.file_id();

                    ret = _PutFile("",msg.file_contents(),msg.file_contents().size(),file_id);
                    if(ret == false)
                    {
                        LOG_ERROR("上传语音到文件系统失败");
                        return;
                    }
                }
                break;

                default:
                    LOG_ERROR("消息类型错误");
                    return;
            }
            //3.提取消息的元信息，存储到mysql数据库
            Message msg(message.message_id(),
                message.chat_session_id(),
                message.sender().user_id(),
                message.message().message_type(),
                boost::posix_time::from_time_t(message.timestamp()));

            msg.content(file_content);
            msg.file_id(file_id);
            msg.file_name(file_name);
            msg.file_size(file_size);

            ret = _mysql_handle->insert(msg);
            if(ret == false)
            {
                LOG_ERROR("向数据量插入新消息失!");
                return;
            }
        }

    private:
        //实现用户数据的下载
        bool _GetUser(const string& rid,
            const std::unordered_set<std::string>& user_id_lists,
            std::unordered_map<std::string,UserInfo>& user_data_lists)
        {
            //获取用户子服务
            auto channel = _mm_channel->choose(_user_name_service); //获取信道
            if(!channel)
            {
                LOG_ERROR("未找到用户子服务节点");
                return false;
            }
            //实例化rpc调用客户端对象，发起rpc调用
            zrb::UserService_Stub stub(channel.get());
            zrb::GetMultiUserInfoReq req;
            req.set_request_id(rid);
            for(auto it : user_id_lists) //存入文件id
            {
                req.add_users_id(it);
            }

            brpc::Controller cntl;
            zrb::GetMultiUserInfoRsp rsp;
            stub.GetMultiUserInfo(&cntl, &req, &rsp, nullptr);

            if(cntl.Failed() || rsp.success() == false)
            {
                LOG_ERROR("用户子服务调用失败 - {}",cntl.ErrorText());
                return false;
            }

            const auto& umap = rsp.users_info();
            for(auto it = umap.begin(); it != umap.end(); ++it) //存入数据
            {
                user_data_lists.insert(std::make_pair(it->first,it->second));
            }

            return true;
        }
        //实现文件数据的下载
        bool _GetFile(const string& rid,
            const std::unordered_set<std::string>& file_id_lists,
            std::unordered_map<std::string,std::string>& file_data_lists)
        {
            //获取文件子服务
            auto channel = _mm_channel->choose(_file_name_service); //获取信道
            if(!channel)
            {
                LOG_ERROR("未找到文件子服务节点");
                return false;
            }
            //实例化rpc调用客户端对象，发起rpc调用
            zrb::FileService_Stub stub(channel.get());
            zrb::GetMultiFileReq req;
            req.set_request_id(rid);
            for(auto it : file_id_lists) //存入文件id
            {
                req.add_file_id_list(it);
            }

            brpc::Controller cntl;
            zrb::GetMultiFileRsp rsp;
            stub.GetMultiFile(&cntl, &req, &rsp, nullptr);

            if(cntl.Failed() || rsp.success() == false)
            {
                LOG_ERROR("文件子服务调用失败 - {}",cntl.ErrorText());
                return false;
            }

            const auto& fmap = rsp.file_data();
            for(auto it = fmap.begin(); it != fmap.end(); ++it) //存入数据
            {
                file_data_lists.insert(std::make_pair(it->first,it->second.file_content()));
            }

            return true;
        }
        //实现文件数据的上传
        bool _PutFile(const std::string& filename,
            const std::string& body,
            const int64_t fsize,
            std::string& file_id)
        {
            //上传头像文件到文件子服务，
            auto channel = _mm_channel->choose(_file_name_service); //获取信道
            if(!channel)
            {
                LOG_ERROR("未找到文件子服务节点");
                return false;
            }
            //实例化rpc调用客户端对象，发起rpc调用
            zrb::FileService_Stub stub(channel.get());
            zrb::PutSingleFileReq req;

            req.mutable_file_data()->set_file_name(filename);
            req.mutable_file_data()->set_file_size(fsize);
            req.mutable_file_data()->set_file_content(body);

            brpc::Controller cntl;
            zrb::PutSingleFileRsp rsp;
            stub.PutSingleFile(&cntl, &req, &rsp, nullptr);

            if(cntl.Failed() || rsp.success() == false)
            {
                LOG_ERROR("{} 网络子服务调用失败 - {}",cntl.ErrorText());
                return false;
            }

            file_id = rsp.file_info().file_id();
            return true;
        }  


    private:
        //odb框架和mysql操作封装句柄
        MessageTable::ptr _mysql_handle;

        //es用户操作客户端
        ESMessage::ptr _es_handle;

        ServiceManager::ptr _mm_channel; //RPC信道管理对象,进行文件子服务的rpc，请求进行头像的文件下载
        std::string _file_name_service;  //文件子服务的名称
        std::string _user_name_service;  //用户子服务的名称
    };

    // （2）.创建rpc服务器类，搭建服务器
    //  （3）.向服务器中添加rpc子服务对象 -- 告诉服务器收到什么请求用哪个接口处理
    class MessageServer
    {
    public:
        using ptr = shared_ptr<MessageServer>;
        MessageServer(const Registry::ptr& service_registry, 
            const Discovery::ptr& service_discoverer, 
            const std::shared_ptr<brpc::Server> &rpc_server,
            const std::shared_ptr<odb::core::database>& mysql_odb,
            const std::shared_ptr<elasticlient::Client>& es_client,
            const MQClient::ptr& mq_client)
            :_service_discoverer(service_discoverer)
            ,_service_registry(service_registry)
            ,_rpc_server(rpc_server)
            ,_mysql_odb(mysql_odb)
            ,_es_client(es_client)
            ,_mq_client(mq_client)
        {
        }

        void start()
        {
            _rpc_server->RunUntilAskedToQuit(); // 休眠等待运行结束
        }

        ~MessageServer()
        {
        }

    private:
        Discovery::ptr _service_discoverer;                 //服务发现对象
        Registry::ptr _service_registry;                    // etcd服务器注册类
        std::shared_ptr<brpc::Server> _rpc_server;          // brpc服务器对象
        std::shared_ptr<odb::core::database> _mysql_odb;
        std::shared_ptr<elasticlient::Client> _es_client;
        MQClient::ptr _mq_client;                           //消息队列
    };

    // SpeechServer构造过程参数太多，使用建造者模式
    class MessageServerBuild
    {
    public:
        //构造mysql客户端
        void make_mysql_object(
            int max_pool,
            const std::string& user,
            const std::string& password,
            const std::string& dbname,
            const std::string& host,
            int port,
            const std::string& cset)
        {
            _mysql_odb = ODBFactory::create(max_pool,user,password,dbname,host,port,cset);
        }

        //构造es客户端
        void make_es_object(std::string& host)
        {
            _es_client = ESClientFactory::create(host);
        }

        //构造消息队列客户端
        void make_mq_object(const std::string &user, 
            const std::string& passwd,
            const std::string& host,
            const std::string &exchange,
            const std::string &queue,
            const std::string& binding_key)
        {
            _exchange = exchange; 
            _queue_name = queue;
            _mq_client = std::make_shared<MQClient>(user,passwd,host); 
            _mq_client->declareComponents(exchange,queue,binding_key); //绑定交换机和队列
        }


        //用于构造服务发现客户端&信道管理对象
        void make_discovery_object(const std::string& reg_host,
            const std::string& base_service_name,
            const std::string& file_service_name,
            const std::string& user_name_service)
        {
            _file_service_name = file_service_name;
            _user_name_service = user_name_service;
            //信道管理对象
            _mm_channel = std::make_shared<ServiceManager>();
            _mm_channel->declared(file_service_name);
            _mm_channel->declared(user_name_service);
            auto put_cb = std::bind(&ServiceManager::onServiceOnline, _mm_channel.get(), std::placeholders::_1, std::placeholders::_2);
            auto del_cb = std::bind(&ServiceManager::onServiceOffline, _mm_channel.get(), std::placeholders::_1, std::placeholders::_2);
            //2. 构造服务发现对象
            _service_discoverer = std::make_shared<Discovery>(reg_host, base_service_name, put_cb, del_cb);
        }

        // 构造etcd服务注册对象
        // 网络Ip、注册的服务名称、注册的服务地址
        void make_reg_object(const std::string &host, const std::string &name, const std::string &access_host)
        {
            _service_registry = std::make_shared<Registry>(host);
            _service_registry->registry(name, access_host); // 服务注册
        }
        // 构造brpc服务对象
        // 端口 超时时间 线程数量
        void make_rpc_object(uint16_t port, 
            uint32_t timeout, 
            uint8_t thread_num)
        {
            _rpc_server = std::make_shared<brpc::Server>();

            // 向服务器增加一个UserServerImpl服务，SpeechServiceImpl服务是自己实现的
            MessageServiceImpl *echo_service = new MessageServiceImpl(_mysql_odb,_es_client,_mm_channel,_file_service_name,_user_name_service);
            // brpc::ServiceOwnership::SERVER_DOESNT_OWN_SERVICE 表示添加服务失败，服务器也不会删除服务对象
            // brpc::ServiceOwnership::SERVER_OWNS_SERVICE 表示添加服务失败时，服务器负责删除服务对象
            int ret = _rpc_server->AddService(echo_service, brpc::ServiceOwnership::SERVER_OWNS_SERVICE);
            if (ret == -1)
            {
                LOG_ERROR("添加Rpc服务失败！");
                abort();
            }

            // 启动服务器
            brpc::ServerOptions options;
            options.idle_timeout_sec = timeout;       // 连接空闲超时时间-超时后连接被关闭
            options.num_threads = thread_num;         // io线程数量
            ret = _rpc_server->Start(port, &options); // 监听的端口
            if (ret == -1)
            {
                LOG_ERROR("rpc服务器启动失败");
                abort();
            }

            //设置消息队列的消费函数
            auto callback = std::bind(&MessageServiceImpl::onMessage,
                echo_service,
                std::placeholders::_1,
                std::placeholders::_2);
            _mq_client->consume(_queue_name,callback);
        }

        MessageServer::ptr build()
        {
            if (!_mysql_odb)
            {
                LOG_ERROR("还未初始化mysql数据库模块");
                abort();
            }     
            if (!_es_client)
            {
                LOG_ERROR("还未初始化es搜索引擎模块");
                abort();
            }
            if(!_mq_client)
            {
                LOG_ERROR("还未初始化服务注册消息队列客户端模块");
                abort();
            }
            if(!_mm_channel)
            {
                LOG_ERROR("还未初始化信道管理模块");
                abort();
            }
            if(!_service_discoverer)
            {
                LOG_ERROR("还未初始化服务发现模块");
                abort();
            }
            if (!_rpc_server)
            {
                LOG_ERROR("还未初始化rpc服务模块");
                abort();
            }
            if (!_service_registry)
            {
                LOG_ERROR("还未初始化服务注册客户端模块");
                abort();
            }

            MessageServer::ptr server = std::make_shared<MessageServer>(_service_registry,
                _service_discoverer,
                _rpc_server,
                _mysql_odb,
                _es_client,
                _mq_client);
            return server;
        }

    private:
        std::string _file_service_name;                    //服务地址
        ServiceManager::ptr _mm_channel;                     //RPC信道管理对象
        Discovery::ptr _service_discoverer;                 //服务发现对象
        Registry::ptr _service_registry;                    // etcd服务器注册类
        std::shared_ptr<brpc::Server> _rpc_server;         // brpc服务器对象
        std::shared_ptr<odb::core::database> _mysql_odb;
        std::shared_ptr<elasticlient::Client> _es_client;

        MQClient::ptr _mq_client;                
        std::string _exchange;                                  //交换机名称
        std::string _queue_name;                                //队列名称
        std::string _user_name_service;                         //用户管理子服务
    };
};
